//===========================================================================================
// MbCompression, Complete compression library for ASP.NET 2.0-3.5 (VS2005-VS2008)
// Developed by: Miron Abramson. http://blog.mironabramson.com
// Project site: http://www.codeplex.com/MbCompression
// File last update: 15-12-09
//===========================================================================================


#region Using

using System;
using System.Web;
using System.IO;

#endregion

namespace Miron.Web.MbCompression
{
    /// <summary>
    /// HttpModule to compress the output of System.Web.UI.Page handler using gzip/deflate algorithm,
    /// corresponding to the client browser support.
    /// <para>
    /// </para>
    /// </summary>
    public sealed class MbCompressionModule : IHttpModule
    {
        Settings settings;

        #region IHttpModule Members

        /// <summary>
        /// Release resources used by the module (Nothing realy in our case), but must implement (interface).
        /// </summary>
        void IHttpModule.Dispose()
        {
            // Nothing to dispose in our case;
        }

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="context"></param>
        void IHttpModule.Init(HttpApplication context)
        {
            settings = Settings.Instance;
            context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
            context.PreSendRequestHeaders += context_PreSendRequestHeaders;
        }

        #endregion

        #region  // Page Compression

        /// <summary>
        /// Handles the PreRequestHandlerExecute event.
        /// The compression moved to this step to catch Server.Transfer operation
        /// </summary>
        /// <param name="sender">The object that raised the event (HttpApplication)</param>
        /// <param name="e">The event data</param>
        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;

            if (app.Context == null || app.Context.Response == null)
                return;

            // This part of the module compress only handlers from type System.Web.UI.Page
            // Other types such JavaScript or CSS files will be compressed in an httpHandelr.
            // Here we check if the current handler if a Page handler, if so, we compress it.
            if (app.Context.CurrentHandler is System.Web.UI.Page && app.Context.Response != null)
            {
                // Check if the path is not excluded.
                if (!settings.IsValidPath(app.Request.AppRelativeCurrentExecutionFilePath))
                    return;

                if (Util.IsToolkitScriptManagerCombiner(app.Request))
                    return;

                if (settings.CompressPage && !Util.IsContainExcludedParamValue(app.Context) && !(Util.IsMsAjaxRequest(app.Context) && settings.MSAjaxVersion < 3.5))
                {
                    EncodingManager encodingMgr = new EncodingManager(app.Context);

                    if (encodingMgr.IsEncodingEnabled)
                    {
                        // Add preferredEncoding to the context.items for use later in the pipeline
                        app.Context.Items.Add("preferredEncoding", encodingMgr.PreferredEncoding);
                        //Add the compression filter
                        encodingMgr.CompressResponse();
                    }
                }

                if (settings.AutoMode && !Util.IsMsAjaxRequest(app.Context))
                {
                    bool processCss = settings.CompressCSS || settings.MinifyContent || settings.CombineCSS;
                    bool processJs = settings.CompressJavaScript || settings.MinifyContent;
                    app.Response.Filter = new AutoModeFilterStream(app.Response.Filter, app.Response.ContentEncoding, processJs, processCss, settings.CombineCSS, settings.CombineHeaderScripts);
                }
            }
        }


        /// <summary>
        /// Check before sending the headers, if the response marked as compressed, so add the correct "Content-encoding"
        /// header.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void context_PreSendRequestHeaders(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;

            if (app.Context == null || app.Context.Response == null)
                return;

            // The current handler is not really page content.
            if (!Util.IsUIPageContentType(app.Context.Response.ContentType) ||
                app.Context.Response.StatusCode == 500)
            {
                app.Context.Items.Remove("preferredEncoding");
            }
            else
            {
                string preferredEncoding = app.Context.Items["preferredEncoding"] as string;
                if (!string.IsNullOrEmpty(preferredEncoding))
                {
                    app.Context.Response.AppendHeader("Content-encoding", preferredEncoding);
                    app.Context.Items.Remove("preferredEncoding");
                }
            }
        }
        #endregion
    }
}